﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using VEExtended;
using System.Xml.Linq;
using Microsoft.VirtualEarth.MapControl;
using System.IO;
using System.Collections;

namespace IKE_painter
{
    public partial class MainPage : UserControl
    {
        //omezeni dulezitosti slov a stranek
        private readonly Int32 PAGES_WITH_SEARCHED_TERM_IMPORTANCE = 100;
        private readonly Int32 WORDS_WEIGHT_IMPORTANCE = 100;

        //maximalni pocet ,,novych bublin,,
        private readonly Int32 MAX_RESULTS = 8;

        //limity WOP a PW souboru
        private readonly Int32 PW_LIMIT = 31817;
        private readonly Int32 WOP_LIMIT = 4844;

        //pocty zaznamu v jednotlivych WOP a PW souborech
        private readonly Int32 PW_RECORDS_PER_FILE = 50;
        private readonly Int32 WOP_RECORDS_PER_FILE = 100;

        //volat pouze v předmětu GAL
        private readonly Boolean IS_GAL_EXTENSION = false;

        //vyraz zadany uzivatelem
        String searchedTerm = String.Empty;

        //id tohoto vyrazu
        String idOfSearchedTerm = String.Empty;

        //id stranky, na ktere je hledany term nejdulezitejsi
        Int32 bestPageIDForSearchedTerm = 0;

        //id stranek, na kterych je hledany term dulezity
        List<String> idsOfPagesWithSearchedTerm = new List<string>();

        //dulezite slova na strankach (viz prechozi)
        List<ResultWord> resultWordsIDs = new List<ResultWord>();

        // list termu pro predani do grafu
        List<Term> termList = new List<Term>();

        //pomocny iterator pro prochezeni kolekce
        Int32 idsOfPagesWithSearchedTermIterator = 0;

        //promena pro predani id prave kliknuteho termu
        Int32 clickedTermID = 0;

        //indexove soubory a promenne indikujici, zda jsou tyto soubory zcela nacteny
        XDocument wordsIndexFile;
        Boolean isWordsIndexFileReady = false;
        XDocument pagesIndexFile;
        Boolean isPagesIndexFileReady = false;
        XDocument stopWordsIndexFile;
        Boolean isStopWordsIndexFileReady = false;
        XDocument linksIndexFile;
        Boolean isLinksIndexFileReady = false;

        //promenne soubory pro nacitani WOP a PW souboru a cisla predchazejicich zaznamu
        // cele to slouzi k tomu, aby se nemusel znovu otevirat a nacitat soubor, ze ktereho
        // se cetlo v minulem cyklu
        XDocument wopFile;
        Int32 lastIndexOfWOPFile = 0;
        Int32 currentIndexOfWOPFile = 0;
        XDocument pwFile;
        Int32 lastIndexOfPWFile = 0;
        Int32 currentIndexOfPWFile = 0;

        //ciselnik barev
        Color[] lovColors = {Color.FromArgb(255,176,23,31),
                                Color.FromArgb(255,238,106,167),
                                Color.FromArgb(255,191,62,255),	
                                Color.FromArgb(255,67,110,238),
                                Color.FromArgb(255,79,148,205),
                                Color.FromArgb(255,50,205,50),
                                Color.FromArgb(255,154,205,50),  	
                                Color.FromArgb(255,238,238,0),
                                Color.FromArgb(255,238,0,0),
                                Color.FromArgb(255,238,180,34),
                                Color.FromArgb(255,255,140,0),	
                                Color.FromArgb(255,238,44,44),
                                Color.FromArgb(255,176,176,176)};

        //index posledni pouzite barvy
        Int32 lastColorIndex = 0;

        MapLayer mp = new MapLayer();

        public MainPage()
        {
            InitializeComponent();

            LoadIndexFiles();

            graph.SetTileLayer(VEExtended.TileMap.Mode.Null); //mapy tam nechceme, vyklidím plochu
            graph.SetMapView(0, 0, 20);
            if (IS_GAL_EXTENSION)
            {
                dok.Visibility = Visibility.Collapsed;
            }
            else
            {
                gal.Visibility = Visibility.Collapsed;
                galComponents.Visibility = Visibility.Collapsed;
                galRemoveNode.Visibility = Visibility.Collapsed;
            }
        }

        private void graph_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            graph.SetBackground(); //maluju nabílo
        }

        //metoda vytvori z predaneho stringu odkaz na wiki
        private String CreateWikipediaURL(String s)
        {
            s.Replace(' ', '_');

            s = "http://cs.wikipedia.org/wiki/" + s;

            return s;
        }

        //zjisti, jestli predane id nalezi stop slovu
        private bool IsStopWord(String wordId)
        {
            var result = (from c in stopWordsIndexFile.Elements("Words").Elements("Word")

                          where (string)c.Element("id").Value == wordId

                          select c).Count();

            if ((int)result == 0) return false;
            else return true;
        }

        /***** 0. nacteni indexovych souboru slov a stranek *****/
        private void LoadIndexFiles()
        {
            if (!IS_GAL_EXTENSION)
            {
                WebClient wc = new WebClient();
                wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc.OpenReadCompleted += wc_OpenReadWordsXMLCompleted;
                wc.OpenReadAsync(new Uri("crawlerOutputFiles/Words.xml", UriKind.Relative));

                WebClient wc2 = new WebClient();
                wc2.OpenReadCompleted += wc_OpenReadPagesXMLCompleted;
                wc2.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc2.OpenReadAsync(new Uri("crawlerOutputFiles/Pages.xml", UriKind.Relative));

                WebClient wc3 = new WebClient();
                wc3.OpenReadCompleted += wc_OpenReadStopWordsXMLCompleted;
                wc3.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc3.OpenReadAsync(new Uri("crawlerOutputFiles/StopWords.xml", UriKind.Relative));
            }
            else
            {
                WebClient wc4 = new WebClient();
                wc4.OpenReadCompleted += wc_OpenReadLinksXMLCompleted;
                wc4.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc4.OpenReadAsync(new Uri("crawlerOutputFiles/Links.xml", UriKind.Relative));

                // CreateTermsFromPages();
                // CreateTermsFromPages();
            }
        }

        private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            // Progress Updates
            MyProgress.Value = e.ProgressPercentage;
        }

        private void wc_OpenReadWordsXMLCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                graph.MessageNew(e.Error.Message);
                return;
            }
            try
            {
                using (Stream s = e.Result)
                {
                    wordsIndexFile = XDocument.Load(s);

                    isWordsIndexFileReady = true;
                }
            }
            catch (Exception ex) { graph.Message(ex.Message); }
        }

        private void wc_OpenReadPagesXMLCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                graph.MessageNew(e.Error.Message);
                return;
            }
            try
            {
                using (Stream s = e.Result)
                {
                    pagesIndexFile = XDocument.Load(s);

                    isPagesIndexFileReady = true;
                }
            }
            catch (Exception ex) { graph.Message(ex.Message); }
        }

        private void wc_OpenReadStopWordsXMLCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                graph.MessageNew(e.Error.Message);
                return;
            }
            try
            {
                using (Stream s = e.Result)
                {
                    stopWordsIndexFile = XDocument.Load(s);

                    isStopWordsIndexFileReady = true;
                }
            }
            catch (Exception ex) { graph.Message(ex.Message); }
        }


        private void wc_OpenReadLinksXMLCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                graph.MessageNew(e.Error.Message);
                return;
            }
            try
            {
                using (Stream s = e.Result)
                {
                    linksIndexFile = XDocument.Load(s);

                    isLinksIndexFileReady = true;
                    CreateTermsFromPages();
                }
            }
            catch (Exception ex) { graph.Message(ex.Message); }
        }

        /***** 1. najde id prave vyhledavaneho termu *****/
        private void FindSearchedTermsId()
        {
            while (!isWordsIndexFileReady) { } //cekaci smyka pokud index jeste neni ready

            if (idOfSearchedTerm == String.Empty)
            {
                var query = from c in wordsIndexFile.Elements("Words").Elements("word")

                            where (string)c.Attribute("name").Value == searchedTerm

                            select c;

                foreach (var el in query)
                {
                    idOfSearchedTerm = el.Attribute("id").Value;
                }

                if (idOfSearchedTerm != String.Empty)
                {
                    if (IsStopWord(idOfSearchedTerm))
                    {
                        try
                        {
                            //je to stop slovo
                            throw (new Exception("Slovo '" + searchedTerm + "' je příliš běžné. Zkuste hledat jiné."));
                        }
                        catch (Exception ex) { graph.Message(ex.Message); }
                    }
                    else
                    {
                        FindPagesForWordId();
                    }
                }
                else
                {
                    //nebylo nalezeno
                    graph.MessageNew("Hledané slovo '" + searchedTerm + "' nebylo nalezeno");
                }
            }
            else
            {
                //id uz zname, pokracujeme dal
                FindPagesForWordId();
            }
        }
        /****************************************************************************/

        /***** 2. najde vsechny stranky s vyhledavanym termem ******/
        private void FindPagesForWordId()
        {
            Int32 nidOfSearchedTerm = Convert.ToInt32(idOfSearchedTerm);
            currentIndexOfPWFile = nidOfSearchedTerm / PW_RECORDS_PER_FILE + 1;

            //rozah vzorku dat
            if (currentIndexOfPWFile <= PW_LIMIT)
            {
                WebClient wc = new WebClient();
                wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc.OpenReadCompleted += wc_OpenReadPWXMLCompleted;
                wc.OpenReadAsync(new Uri("crawlerOutputFiles/PagesWeight/pw" + currentIndexOfPWFile.ToString() + ".xml", UriKind.Relative));
            }
            else
            {
                throw (new Exception("Hledané slovo nebylo nalezeno na tomto vzorku dat"));
            }
        }

        private void wc_OpenReadPWXMLCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                graph.MessageNew(e.Error.Message);
                return;
            }
            try
            {
                using (Stream s = e.Result)
                {
                    //je to ten samy soubor co minule?
                    if (currentIndexOfPWFile != lastIndexOfPWFile)
                    {
                        //pokud neni, tak znova nacteme
                        pwFile = XDocument.Load(s);
                        lastIndexOfPWFile = currentIndexOfPWFile;
                    }

                    var query = from c in pwFile.Elements("Words").Elements("word")

                                where (string)c.Element("id").Value == idOfSearchedTerm

                                select c;

                    foreach (var el in query)
                    {
                        var innerQuery = from d in el.Elements("page")

                                         where Convert.ToInt32(d.Element("weight").Value) > PAGES_WITH_SEARCHED_TERM_IMPORTANCE

                                         select d;

                        foreach (var iel in innerQuery)
                        {
                            idsOfPagesWithSearchedTerm.Add(iel.Element("id").Value);

                            //hledame id s maximalni vahou jako vyslednou stranku pro hledany term
                            //neboli id stranky, na ktere je tento term nejdulezitejsi
                            if (Convert.ToInt32(iel.Element("weight").Value) > bestPageIDForSearchedTerm)
                            {
                                bestPageIDForSearchedTerm = Convert.ToInt32(iel.Element("id").Value);
                            }
                        }
                    }

                    if (idsOfPagesWithSearchedTerm.Count != 0)
                    {
                        FindWordsWithWeightsForPages();
                    }
                    else
                    {
                        //slovo neni na zadnych strankach (vzhledem k nastavene dulezitosti)
                        throw (new Exception("Hledané slovo '" + searchedTerm + "' nebylo nalezeno"));
                    }
                }
            }
            catch (Exception ex) { graph.MessageNew(ex.Message); }
        }
        /****************************************************************************/

        /****** 3. najde všechny důležitá slova na stránkách *****/
        private void FindWordsWithWeightsForPages()
        {
            Int32 idOfPage = Convert.ToInt32(idsOfPagesWithSearchedTerm[idsOfPagesWithSearchedTermIterator]);
            currentIndexOfWOPFile = idOfPage / WOP_RECORDS_PER_FILE + 1;

            //rozsah vzorku dat
            if (currentIndexOfWOPFile <= WOP_LIMIT)
            {
                WebClient wc = new WebClient();
                wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc.OpenReadCompleted += wc_OpenReadWOPXMLCompleted;
                wc.OpenReadAsync(new Uri("crawlerOutputFiles/WordsOnPages/wop" + currentIndexOfWOPFile.ToString() + ".xml", UriKind.Relative));
            }
            else
            {
                //protoze stranky jsou podle velikosti, vsechny dalsi uz budou taky vetsi, tzn.
                // muzeme smele pokrocit dal

                ManageResults();
            }
        }

        private void wc_OpenReadWOPXMLCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                graph.MessageNew(e.Error.Message);
                return;
            }
            try
            {
                using (Stream s = e.Result)
                {
                    //je to ten samy soubor co minule?
                    if (currentIndexOfWOPFile != lastIndexOfWOPFile)
                    {
                        //pokud neni, tak znova nacteme
                        wopFile = XDocument.Load(s);
                        lastIndexOfWOPFile = currentIndexOfWOPFile;
                    }

                    String currentPageID = idsOfPagesWithSearchedTerm[idsOfPagesWithSearchedTermIterator];

                    var query = from c in wopFile.Elements("Pages").Elements("Page")

                                where (string)c.Element("id").Value == currentPageID

                                select c;

                    foreach (var el in query)
                    {
                        var innerQuery = from d in el.Elements("Word")

                                         where Convert.ToInt32(d.Element("weight").Value) > WORDS_WEIGHT_IMPORTANCE

                                         select d;

                        foreach (var iel in innerQuery)
                        {
                            ResultWord word = new ResultWord();
                            word.wordID = iel.Element("id").Value;
                            word.weight = iel.Element("weight").Value;
                            word.pageID = currentPageID;

                            resultWordsIDs.Add(word);
                        }
                    }

                    idsOfPagesWithSearchedTermIterator++;

                    if (idsOfPagesWithSearchedTermIterator < idsOfPagesWithSearchedTerm.Count)
                    {
                        //dalsi stranka
                        FindWordsWithWeightsForPages();
                    }
                    else
                    {
                        ManageResults();
                    }
                }
            }
            catch (Exception ex) { graph.Message(ex.Message); }
        }
        /****************************************************************************/

        /***** 4. zkontroluje kolik je vysledku a pripadne vybere pouze ty nejdulezitejsi *****/
        private void ManageResults()
        {
            //setridime vysledky
            resultWordsIDs.Sort();

            //nyni kolekci vysledku zmensime tak, ze:
            // - vybereme pouze MAX_RESULT vysledku
            // - odstranime vsechny slova stejna jako hledane
            List<ResultWord> topResultsWithNoWordSameAsSearched = new List<ResultWord>();

            //prochazime kolekci on nej vysledku po nejhorsi
            for (int i = resultWordsIDs.Count - 1; i >= 0; i--)
            {
                //jestlize to neni hledany term, pak ho bereme
                if (resultWordsIDs[i].wordID != idOfSearchedTerm && !IsStopWord(resultWordsIDs[i].wordID))
                {
                    bool isAlreadyThere = false; //je uz toto slovo v kolekci?
                    foreach (ResultWord word in topResultsWithNoWordSameAsSearched)
                    {
                        if (word.wordID == resultWordsIDs[i].wordID)
                        {
                            isAlreadyThere = true;
                            break;
                        }
                    }

                    if (!isAlreadyThere)
                        topResultsWithNoWordSameAsSearched.Add(resultWordsIDs[i]);
                }

                //jestlize jich mame tolik, kolik jsme chteli, pak koncime cyklus
                if (topResultsWithNoWordSameAsSearched.Count == MAX_RESULTS)
                {
                    break;
                }
            }

            resultWordsIDs = topResultsWithNoWordSameAsSearched;

            if (clickedTermID == 0) //kliknulo se znova na koren nebo je to prvni hledani
            {
                ResultWord root = new ResultWord();
                root.wordID = idOfSearchedTerm;
                root.pageID = bestPageIDForSearchedTerm.ToString();
                root.weight = "-1"; //mala vaha zajisti, ze bude koren v kolekci po setrideni jako prvni

                resultWordsIDs.Add(root);

                resultWordsIDs.Sort();
            }

            AddPagesNames();
        }
        /****************************************************************************/

        /***** 5. najde a doplni jmena stranek *****/
        private void AddPagesNames()
        {
            while (!isPagesIndexFileReady) { }

            foreach (ResultWord word in resultWordsIDs)
            {
                var query = from c in pagesIndexFile.Elements("Pages").Elements("Page")

                            where c.Element("id").Value == word.pageID

                            select c;

                foreach (var el in query)
                {
                    word.pageName = el.Element("name").Value;
                }
            }

            CreateTerms();
        }
        /****************************************************************************/

        /***** 6. vytvori termy a vlozi do grafu *****/
        private void CreateTerms()
        {
            Random random = new Random();
            Int32 colorIndex = random.Next(lovColors.Length);

            while (colorIndex == lastColorIndex)
            {
                colorIndex = random.Next(lovColors.Length);
            }

            lastColorIndex = colorIndex;

            foreach (ResultWord word in resultWordsIDs)
            {
                var query = from c in wordsIndexFile.Elements("Words").Elements("word")

                            where (string)c.Attribute("id").Value == word.wordID

                            select c;

                foreach (var el in query)
                {
                    Term t = new Term();

                    t.WordID = Convert.ToInt32(el.Attribute("id").Value);

                    t.Name = el.Attribute("name").Value;

                    t.Bubble = new Bubble();
                    t.Bubble.Color = lovColors[lastColorIndex];
                    t.Bubble.Size = 10;

                    t.Line = new VEExtended.Line();
                    t.Line.Color = lovColors[lastColorIndex];
                    t.Line.Size = 5;

                    t.Text = word.pageName;
                    t.URL = CreateWikipediaURL(word.pageName);

                    if (word.weight == "-1")
                    {
                        t.RootID = 0; //jestlize je to root, pak ukazuje na termID 0 (tj. sam na sebe)

                        //zaroven jeho udaje doplnime do tabulky
                        tbText.Text = t.Text;
                        tbName.Text = t.Name;
                        hbLink.Content = t.URL;
                        if (t.URL != null)
                            hbLink.NavigateUri = new Uri(@t.URL);
                    }
                    else
                    {
                        t.RootID = clickedTermID; //jinak je root ten term, na ktery jsme kliknuli
                    }

                    termList.Add(t);
                }
            }

            graph.AddTermListToGraph(termList);
            graph.RepaintGraph();

            tbSearch.Text = "";

        }
        /****************************************************************************/

        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            if (tbSearch.Text != String.Empty)
            {
                graph.RemoveTermsFromGraph();// vycistit kolekci, vymazat graf

                idOfSearchedTerm = String.Empty;
                idsOfPagesWithSearchedTerm = new List<string>();
                resultWordsIDs = new List<ResultWord>();
                termList = new List<Term>();

                clickedTermID = 0;

                idsOfPagesWithSearchedTermIterator = 0;

                String[] searchedTerms = tbSearch.Text.Split(' ');

                searchedTerm = searchedTerms[0];

                FindSearchedTermsId();
            }
        }

        private void graph_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!IS_GAL_EXTENSION)
            {
                //Po kliknutí na Term načtu jeho data a vypíšu do levého sloupku
                Term tt = graph.getTerm(graph.activeTerm);
                if (tt.WordID != Convert.ToInt32(idOfSearchedTerm)) //neni to ten, ktery jsme hledali minule
                {
                    tbText.Text = tt.Text;
                    tbName.Text = tt.Name;
                    hbLink.Content = tt.URL;
                    if (tt.URL != null)
                        hbLink.NavigateUri = new Uri(@tt.URL);

                    //pro koren uz znova nehledame
                    if (tt.TermID != 0)
                    {
                        searchedTerm = tt.Name;
                        idOfSearchedTerm = tt.WordID.ToString();
                        clickedTermID = tt.TermID;

                        idsOfPagesWithSearchedTerm = new List<string>();
                        resultWordsIDs = new List<ResultWord>();
                        termList = new List<Term>();

                        idsOfPagesWithSearchedTermIterator = 0;

                        FindSearchedTermsId();
                    }
                }
            }
        }

        private void btnClearAll_Click(object sender, RoutedEventArgs e)
        {
            graph.RemoveTermsFromGraph(); // vycistit kolekci, vymazat graf
        }

        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            graph.RepaintGraph(); //překreslení všech Termů v grafu
        }




        /************************************************************************************/
        /*****************************        GAL        ************************************/
        /************************************************************************************/

        private readonly bool BOTH_SIDE_EDGE = true;

        List<Node> nodes = new List<Node>();
        List<Edge> edges = new List<Edge>();
        Floyd_Warshall fw;
        List<int> removedNodes = new List<int>(); //idcka odebranych nodu

        /***** 0. vytvori termy a vlozi do grafu *****/
        private void CreateTermsFromPages()
        {
            while (!isLinksIndexFileReady) { } //cekaci smyka pokud index jeste neni ready

            Random random = new Random();
            Int32 colorIndex = random.Next(lovColors.Length);

            while (colorIndex == lastColorIndex)
            {
                colorIndex = random.Next(lovColors.Length);
            }

            lastColorIndex = colorIndex;

            /***** prohledá LinkXML list *****/
            List<PageFrom> linkList =
                                   (from shape in linksIndexFile.Elements("Links").Elements("PageFrom")
                                    select new PageFrom()
                                    {
                                        ID = Convert.ToInt32(shape.Attribute("id").Value),
                                        pageName = shape.Attribute("name").Value,
                                        PageTo = (from rec in shape.Elements("PageTo")
                                                  select new PageTo()
                                                     {
                                                         ID = Convert.ToInt32(rec.Attribute("id").Value),
                                                         Count = Convert.ToInt32(rec.Attribute("count").Value)
                                                     }).ToList<PageTo>()
                                    }).ToList<PageFrom>();


            /***** zkontroluje jestli každý pageTo existuje jako pageFrom *****/
            //1. projít všechny PageFrom z linkList
            //2. projít všechny PageFrom.PageTo
            //3. u každého PageFrom.PageTo zjistit jestli je ID obsažen v linkListu
            //4. pokud není, vymazat PageTo PageFrom


            foreach (PageFrom pf in linkList)//1.
            {
                List<PageTo> PageToAdd = new List<PageTo>();
                foreach (PageTo pt in pf.PageTo)//2.
                {
                    Boolean exist = false;
                    for (int i = 0; i < linkList.Count; i++) //3.
                        if (linkList[i].ID == pt.ID) { exist = true; }

                    if (exist == true) PageToAdd.Add(pt); //4.
                }
                pf.PageTo = PageToAdd;
            }

            /*****  naplní termList/nodes/edges *****/
            foreach (PageFrom pf in linkList)
            {
                Node nodeRoot = new Node(pf.ID);
                nodes.Add(nodeRoot);

                Term tt = new Term();
                tt.TermID = pf.ID;

                foreach (PageTo pt in pf.PageTo)
                {
                    Node nodeTo = new Node(pt.ID);

                    edges.Add(new Edge(nodeRoot, nodeTo, 1));
                    if (BOTH_SIDE_EDGE)
                        edges.Add(new Edge(nodeTo, nodeRoot, 1));
                    TermChild tch = new TermChild();
                    tch.ID = pt.ID;
                    tch.SizeLine = pt.Count;
                    tt.Child.Add(tch);
                }
                tt.Name = pf.pageName;// + " (" + pf.ID.ToString() + ")";
                tt.Bubble = new Bubble();
                tt.Bubble.Color = Color.FromArgb(255, 238, 180, 34);
                tt.Bubble.Size = 6;
                tt.Line = new VEExtended.Line();
                tt.Line.Color = lovColors[lastColorIndex]; //Color.FromArgb(255, 238, 180, 34);
                tt.Line.Size = 4;
                termList.Add(tt);
            }

            cbFirst.Items.Clear();
            cbSecond.Items.Clear();
            cbNodes.Items.Clear();
            cbFirst.DisplayMemberPath = "Name";
            cbFirst.ItemsSource = termList.OrderBy(t => t.Name);
            cbSecond.DisplayMemberPath = "Name";
            cbSecond.ItemsSource = termList.OrderBy(t => t.Name);
            cbNodes.DisplayMemberPath = "Name";
            cbNodes.ItemsSource = termList.OrderBy(t => t.Name);


            /*****  přidání do grafu a vykreslení *****/
            graph.AddTermListToGraph(termList, false);
            graph.GAL_PaintGraph();
        }

        private void btnFindPath_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Term tFirst = (Term)cbFirst.SelectedItem;
                Term tSecond = (Term)cbSecond.SelectedItem;

                /*****  Floyd_Warshall part *****/
                fw = new Floyd_Warshall(nodes.ToArray(), edges.ToArray());
                fw.calcShortestPaths();

                tbName.Text = "Floyd-Warshall";
                graph.GAL_RepaintGraph2();

                List<Int32> sorthestNodePath = fw.getShortestPath(tFirst.TermID, tSecond.TermID);

                if (sorthestNodePath.Count == 0)
                {
                    tbText.Text = "Cesta neexistuje";
                }
                else
                {
                    tbText.Text = "Délka: " + fw.getShortestDistance(tFirst.TermID, tSecond.TermID).ToString();
                    tbText.Text += "\n\nCesta: \n";

                    graph.GAL_PaintPath(sorthestNodePath.ToArray());
                    for (int i = 0; i < sorthestNodePath.Count; i++)
                        tbText.Text += "  -" + graph.getTerm(sorthestNodePath[i]).Name + "\n";
                }
            }
            catch (Exception ex) { graph.Message(ex.Message); }
        }

        private void btnFindComponents_Click(object sender, RoutedEventArgs e)
        {

            ///***** prohledá LinkXML list *****/
            List<PageFrom> linkList =
                                   (from shape in linksIndexFile.Elements("Links").Elements("PageFrom")
                                    select new PageFrom()
                                    {
                                        ID = Convert.ToInt32(shape.Attribute("id").Value),
                                        pageName = shape.Attribute("name").Value,
                                        PageTo = (from rec in shape.Elements("PageTo")
                                                  select new PageTo()
                                                  {
                                                      ID = Convert.ToInt32(rec.Attribute("id").Value),
                                                      Count = Convert.ToInt32(rec.Attribute("count").Value)
                                                  }).ToList<PageTo>()
                                    }).ToList<PageFrom>();


            ///***** zkontroluje jestli každý pageTo existuje jako pageFrom *****/
            ////1. projít všechny PageFrom z linkList
            ////2. projít všechny PageFrom.PageTo
            ////3. u každého PageFrom.PageTo zjistit jestli je ID obsažen v linkListu
            ////4. pokud není, vymazat PageTo PageFrom


            foreach (PageFrom pf in linkList)//1.
            {
                List<PageTo> PageToAdd = new List<PageTo>();
                foreach (PageTo pt in pf.PageTo)//2.
                {
                    Boolean exist = false;
                    for (int i = 0; i < linkList.Count; i++) //3.
                        if (linkList[i].ID == pt.ID) { exist = true; }

                    if (exist == true) PageToAdd.Add(pt); //4.
                }
                pf.PageTo = PageToAdd;
            }
            nodes.Clear();
            edges.Clear();

            /*****  naplní nodes/edges *****/
            foreach (PageFrom pf in linkList)
            {
                if (removedNodes.Contains(pf.ID)) continue;

                Node nodeRoot = new Node(pf.ID);
                nodes.Add(nodeRoot);

                foreach (PageTo pt in pf.PageTo)
                {
                    if (removedNodes.Contains(pt.ID)) continue;
                    Node nodeTo = new Node(pt.ID);

                    edges.Add(new Edge(nodeRoot, nodeTo, 1));
                    if (BOTH_SIDE_EDGE)
                        edges.Add(new Edge(nodeTo, nodeRoot, 1));
                }
            }

            fw = new Floyd_Warshall(nodes.ToArray(), edges.ToArray());
            GraphComponentsSearch gcs = new GraphComponentsSearch();
            int componentsCount = gcs.Compute(fw);
            int componentsCountWithoutAloneNodes = componentsCount;
            List<int> aloneNodes = new List<int>();
            for (int i = 0; i < nodes.Count; i++)
            {
                bool alone = true;
                for (int j = 0; j < nodes.Count; j++)
                {
                    if (fw.D[i, j] != 0 && fw.D[i, j] != int.MaxValue)
                    {
                        alone = false;
                        break;
                    }
                }
                if (alone)
                {
                    aloneNodes.Add(nodes[i].Name);
                    componentsCountWithoutAloneNodes--;
                }
            }

            Dictionary<int, int> ComponentColor = new Dictionary<int, int>();
            int colorID = 0;
            foreach (Node node in nodes)
            {
                foreach (Term term in termList)
                {
                    if (node.Name == term.TermID)
                    {
                        //term.Bubble.Color = Color.FromArgb(255, (byte)(componentsCount % componentColorID), (byte)(componentsCount % componentColorID), (byte)(componentsCount % componentColorID));
                        if (aloneNodes.Contains(term.TermID))
                            term.Bubble.Color = Color.FromArgb(255, 0, 0, 0);
                        else
                        {
                            int componentColorID;
                            if (ComponentColor.ContainsKey(node.Component))
                            {
                                componentColorID = ComponentColor[node.Component];
                            }
                            else
                            {
                                colorID++;

                                while (colorID >= lovColors.Length)
                                {
                                    colorID -= lovColors.Length;
                                }

                                ComponentColor.Add(node.Component, colorID);
                                componentColorID = colorID;
                            }

                            term.Bubble.Color = lovColors[componentColorID];
                        }
                        //term.Line.Color = lovColors[componentColorID];

                        break;
                    }
                }

            }

            /*****  přidání do grafu a vykreslení *****/
            graph.AddTermListToGraph(termList, false);
            foreach (int removedNode in removedNodes)
            {
                graph.RemoveTermFromGraph(removedNode);
            }
            graph.GAL_RepaintGraph2();

            tbText.Text = "Počet komponent grafu s vynecháním komponent velikosti 1 (černé uzly): " + componentsCountWithoutAloneNodes;
            tbText.Text += "\n\nPočet komponent grafu celkem: " + componentsCount;

        }

        private void btnRemoveNode_Click(object sender, RoutedEventArgs e)
        {
            Term tNode = (Term)cbNodes.SelectedItem;
            removedNodes.Add(tNode.TermID);

            for (int i = 0; i < termList.Count; i++)
            {
                if (termList[i].Name == tNode.Name)
                {
                    termList.RemoveAt(i);
                    break;
                }
            }

            cbFirst.ItemsSource = null;
            cbFirst.Items.Clear();
            cbFirst.DisplayMemberPath = "Name";
            cbFirst.ItemsSource = termList.OrderBy(t => t.Name);
            cbSecond.ItemsSource = null;
            cbSecond.Items.Clear();
            cbSecond.DisplayMemberPath = "Name";
            cbSecond.ItemsSource = termList.OrderBy(t => t.Name);
            cbNodes.ItemsSource = null;
            cbNodes.Items.Clear();
            cbNodes.DisplayMemberPath = "Name";
            cbNodes.ItemsSource = termList.OrderBy(t => t.Name);

            graph.RemoveTermFromGraph(tNode.TermID);
            btnFindComponents_Click(sender, e);
        }

        /****************************************************************************/


        ///Mohlo by se hodit:
        ///
        /// public void AddTermListToGraph(List<Term> termList) - vloží list termů do grafu všechny hned vykreslím
        /// public void AddTermToGraph(Term term) - vloží jeden term do grafu
        /// public void RemoveTermFromGraph(Term term) - odeberu term z grafu
        /// public Int32 deepTerm(Int32 ID, Int32 num) - vrací hloubku(zanoření) termu z grafu ID = ID termu, num = dejte nulu (rekurzivně zvyšuju)
        /// public Term getTerm(Int32 ID) - vrací term podle ID
        /// public void RepaintGraph() - překreslí graf (vykreslí všechny termy v grafu)
        /// public void PaintTermChild(Term term) - vykreslí všechny potomky kořenového termu (např. používám jako onClick na term
        /// public void PaintTerm(Term term) - vykreslím term (neuloží se do grafu), nutné mít zadané souřadnice - Location, jinak vykreslí na 0,0
        /// 

    }
}
